package com.clementheliou.cheliou.dal.core.hibernate.stat.fest.asserter;

import static org.fest.assertions.api.Assertions.assertThat;

import org.fest.assertions.api.AbstractAssert;
import org.hibernate.stat.Statistics;

import com.clementheliou.cheliou.dal.core.fest.assertions.CHeliouDALAssertions;

/**
 * FEST asserter used to make test code about {@link Statistics} instances more readable. It should
 * only be used through the static factory that can be found into the project assertions class (
 * {@link CHeliouDALAssertions}).
 * 
 * @author Clément HELIOU (clement.heliou@gmail.com)
 * @see {@link AbstractAssert};
 * @see {@link CHeliouDALAssertions};
 * @see {@link Statistics}.
 * @since 1.0
 */
public class StatisticsAsserter extends AbstractAssert<StatisticsAsserter, Statistics> {

	/**
	 * Constructor from the {@link Statistics} instance to be asserted.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param actual the {@link Statistics} instance to be asserted.
	 * @since 1.0
	 */
	public StatisticsAsserter(final Statistics actual) {
		super(actual, StatisticsAsserter.class);
	}

	/**
	 * Asserts that the current {@link Statistics} instance has the expected deletions count.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedDeletionsCount the expected deletions count.
	 * @return the asserter instance after this assertion.
	 * @see {@link #getDeletionsCount()}.
	 * @since 1.0
	 */
	public StatisticsAsserter hasDeletionsCount(final Long expectedDeletionsCount) {
		isNotNull();
		assertThat(getDeletionsCount()).isEqualTo(expectedDeletionsCount);
		return this;
	}

	/**
	 * Asserts that the current {@link Statistics} instance has the expected insertions count.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedInsertionsCount the expected insertions count.
	 * @return the asserter instance after this assertion.
	 * @see {@link Statistics#getEntityInsertCount()}.
	 * @since 1.0
	 */
	public StatisticsAsserter hasInsertionsCount(final Long expectedInsertionsCount) {
		isNotNull();
		assertThat(actual.getEntityInsertCount()).isEqualTo(expectedInsertionsCount);
		return this;
	}

	/**
	 * Asserts that the current {@link Statistics} has no conenctions (i.e. that the connections
	 * count is equal to zero).
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @see {@link Statistics#getConnectCount()}.
	 * @since 1.0
	 */
	public StatisticsAsserter hasNoConnections() {
		isNotNull();
		assertThat(actual.getConnectCount()).isZero();
		return this;
	}

	/**
	 * Asserts that the current {@link Statistics} instance has a deletions count equals to zero.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the assert instance after this assertion.
	 * @since 1.0
	 */
	public StatisticsAsserter hasNoDeletions() {
		return hasDeletionsCount(0l);
	}

	/**
	 * Asserts that the current {@link Statistics} instance has an insertions count equals to zero.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the assert instance after this assertion.
	 * @since 1.0
	 */
	public StatisticsAsserter hasNoInsertions() {
		return hasInsertionsCount(0l);
	}

	/**
	 * Asserts that the current {@link Statistics} instance has a selections count equals to zero.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the assert instance after this assertion.
	 * @since 1.0
	 */
	public StatisticsAsserter hasNoSelections() {
		return hasSelectionsCount(0l);
	}

	/**
	 * Asserts that the current {@link Statistics} instance has an update count equals to zero.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the assert instance after this assertion.
	 * @since 1.0
	 */
	public StatisticsAsserter hasNoUpdates() {
		return hasUpdateCount(0l);
	}

	/**
	 * Asserts that the current {@link Statistics} has a positive connections count.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @see {@link Statistics#getConnectCount()}.
	 * @since 1.0
	 */
	public StatisticsAsserter hasPositiveConnectionsCount() {
		isNotNull();
		assertThat(actual.getConnectCount()).isPositive();
		return this;
	}

	/**
	 * Asserts that the current {@link Statistics} instance has the expected selections count.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedSelectionsCount the expected selections count.
	 * @return the asserter instance after this assertion.
	 * @see {@link #getSelectionsCount()}.
	 * @since 1.0
	 */
	public StatisticsAsserter hasSelectionsCount(final Long expectedSelectionsCount) {
		isNotNull();
		assertThat(getSelectionsCount()).isEqualTo(expectedSelectionsCount);
		return this;
	}

	/**
	 * Asserts that the current {@link Statistics} instance has the expected update count.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedUpdateCount the expected update count.
	 * @return the asserter instance after this assertion.
	 * @see {@link #getUpdateCount()}.
	 * @since 1.0
	 */
	public StatisticsAsserter hasUpdateCount(final Long expectedUpdateCount) {
		isNotNull();
		assertThat(getUpdateCount()).isEqualTo(expectedUpdateCount);
		return this;
	}

	/**
	 * Asserts that statistics are enabled for the current {@link Statistics} instance.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @see {@link Statistics#isStatisticsEnabled()}.
	 * @since 1.0
	 */
	public StatisticsAsserter isStatisticsEnabled() {
		isNotNull();
		assertThat(actual.isStatisticsEnabled()).isTrue();
		return this;
	}

	/**
	 * Gets the deletions count for the current {@link Statistics} instance. This is the sum of:
	 * <ul>
	 * <li>the number of deleted entities;</li>
	 * <li>the number of removed collections.</li>
	 * </ul>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the global number of deletions.
	 * @since 1.0
	 */
	private Long getDeletionsCount() {
		return actual.getCollectionRemoveCount() + actual.getEntityDeleteCount();
	}

	/**
	 * Gets the seletions count for the current {@link Statistics} instance. This is the sum of:
	 * <ul>
	 * <li>the number of loaded entities;</li>
	 * <li>the number of loaded collections;</li>
	 * <li>the number of executed queries.</li>
	 * </ul>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the global number of selections.
	 * @since 1.0
	 */
	private Long getSelectionsCount() {
		return actual.getCollectionLoadCount() + actual.getEntityLoadCount() + actual.getQueryExecutionCount();
	}

	/**
	 * Gets the updates count for the current {@link Statistics} instance. This the sum of:
	 * <ul>
	 * <li>the number of updated entities;</li>
	 * <li>the number of updated collections.</li>
	 * </ul>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the global number of updates.
	 * @since 1.0
	 */
	private Long getUpdateCount() {
		return actual.getCollectionUpdateCount() + actual.getEntityUpdateCount();
	}
}
